package com.github.mygreen.supercsv.builder; import static org.junit.Assert.*; import static org.assertj.core.api.Assertions.*; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.Date; import java.util.List; import org.junit.Before; import org.junit.Test; import com.github.mygreen.supercsv.annotation.CsvColumn; import com.github.mygreen.supercsv.annotation.CsvComposition; import com.github.mygreen.supercsv.annotation.CsvOverridesAttribute; import com.github.mygreen.supercsv.annotation.DefaultGroup; import com.github.mygreen.supercsv.annotation.constraint.CsvNumberMax; import com.github.mygreen.supercsv.annotation.constraint.CsvLengthMax; import com.github.mygreen.supercsv.annotation.constraint.CsvDateTimeMax; import com.github.mygreen.supercsv.annotation.constraint.CsvNumberRange; import com.github.mygreen.supercsv.annotation.constraint.CsvRequire; import com.github.mygreen.supercsv.annotation.constraint.CsvUnique; import com.github.mygreen.supercsv.annotation.conversion.CsvLower; import com.github.mygreen.supercsv.annotation.conversion.CsvTrim; import com.github.mygreen.supercsv.annotation.format.CsvDateTimeFormat; import com.github.mygreen.supercsv.exception.SuperCsvInvalidAnnotationException; /** * {@link AnnotationExpander}のテスタ。 * * @since 2.0 * @author T.TSUCHIE * */ public class AnnotationExpanderTest { private AnnotationExpander expander; @Before public void setUp() throws Exception { this.expander = new AnnotationExpander(new AnnotationComparator()); } /** * コンストラクタのテスト - 引数がnullの場合 */ @Test(expected=NullPointerException.class) public void testConstructor_argNull() { new AnnotationExpander(null); fail(); } /** * {@link AnnotationExpander#expand(Annotation[])} のテスタ * <p>引数がnullの場合</p> */ @Test(expected=NullPointerException.class) public void testExpandAnnotationArray_argNull() { expander.expand((Annotation[])null); fail(); } /** * {@link AnnotationExpander#expand(Annotation)} のテスタ * <p>引数がnullの場合</p> */ @Test(expected=NullPointerException.class) public void testExpandAnnotation_argNull() { expander.expand((Annotation)null); fail(); } /** * 通常のアノテーションの展開 */ @Test public void testExpand_normal() { Field field = getSampleField("normal"); Annotation targetAnno = field.getAnnotation(CsvColumn.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvColumn.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.isComposed()).isEqualTo(false); assertThat(expandedAnno.getChilds()).hasSize(0); } } /** * 複数のアノテーションの展開 - 並び順指定の場合 */ @Test public void testExpand_multi() { Field field = getSampleField("multi"); Annotation[] targetAnno = field.getAnnotations(); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(6); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvLower.class); } { ExpandedAnnotation expandedAnno = actual.get(1); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvUnique.class); } { ExpandedAnnotation expandedAnno = actual.get(2); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvDateTimeMax.class); } { ExpandedAnnotation expandedAnno = actual.get(3); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvTrim.class); } { ExpandedAnnotation expandedAnno = actual.get(4); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvColumn.class); } { ExpandedAnnotation expandedAnno = actual.get(5); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvDateTimeFormat.class); } } /** * 繰り返しのアノテーションが1つの場合の展開 */ @Test public void testExpand_repeatSingle() { Field field = getSampleField("repeatSingle"); Annotation targetAnno = field.getAnnotation(CsvLengthMax.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvLengthMax.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.isComposed()).isEqualTo(false); assertThat(expandedAnno.getChilds()).isEmpty(); } } /** * 繰り返しのアノテーションが複数場合の展開 */ @Test public void testExpand_repeatMulti() { Field field = getSampleField("repeatMulti"); Annotation targetAnno = field.getAnnotation(CsvLengthMax.List.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(3); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvLengthMax.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.isComposed()).isEqualTo(false); assertThat(expandedAnno.getChilds()).hasSize(0); CsvLengthMax originalAnno = (CsvLengthMax) expandedAnno.getOriginal(); assertThat(originalAnno.value()).isEqualTo(10); } { ExpandedAnnotation expandedAnno = actual.get(1); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvLengthMax.class); assertThat(expandedAnno.getIndex()).isEqualTo(1); assertThat(expandedAnno.isComposed()).isEqualTo(false); assertThat(expandedAnno.getChilds()).hasSize(0); CsvLengthMax originalAnno = (CsvLengthMax) expandedAnno.getOriginal(); assertThat(originalAnno.value()).isEqualTo(20); } { ExpandedAnnotation expandedAnno = actual.get(2); assertThat(expandedAnno.getOriginal()).isInstanceOf(CsvLengthMax.class); assertThat(expandedAnno.getIndex()).isEqualTo(2); assertThat(expandedAnno.isComposed()).isEqualTo(false); assertThat(expandedAnno.getChilds()).hasSize(0); CsvLengthMax originalAnno = (CsvLengthMax) expandedAnno.getOriginal(); assertThat(originalAnno.value()).isEqualTo(30); } } /** * 合成のアノテーション - 属性のオーバライドなしのシンプルな物。 */ @Test public void testExpand_composeSimple() { Field field = getSampleField("composeSimple"); Annotation targetAnno = field.getAnnotation(ComposeSimple.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeSimple.class); assertThat(expandedAnno.getChilds()).hasSize(8); // expandedAnno.getChilds().forEach(anno -> System.out.println(anno.getOriginal().annotationType().getName())); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvRequire.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberMax.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberMax anno = (CsvNumberMax) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.value()).isEqualTo("30"); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberMax.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberMax anno = (CsvNumberMax) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.value()).isEqualTo("20"); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(7); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 属性のオーバライドなしのシンプルな物。 * ただし、繰り返しがあり */ @Test public void testExpand_composeSimpleRepeat() { Field field = getSampleField("composeSimpleRepeat"); Annotation targetAnno = field.getAnnotation(ComposeSimple.List.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(2); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeSimple.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(8); ComposeSimple compositeAnno = (ComposeSimple) expandedAnno.getOriginal(); assertThat(compositeAnno.value()).isEqualTo("repeat-1"); } { ExpandedAnnotation expandedAnno = actual.get(1); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeSimple.class); assertThat(expandedAnno.getIndex()).isEqualTo(1); assertThat(expandedAnno.getChilds()).hasSize(8); ComposeSimple compositeAnno = (ComposeSimple) expandedAnno.getOriginal(); assertThat(compositeAnno.value()).isEqualTo("repeat-2"); } } /** * 合成のアノテーション - 属性のオーバーライドあり * <p>独自の属性を上書き</p> */ @Test public void testExpand_composeOverrideCustom() { Field field = getSampleField("composeOverrideCustom"); Annotation targetAnno = field.getAnnotation(ComposeOverrideCustom.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeOverrideCustom.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(8); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvRequire.class); CsvRequire anno = (CsvRequire) childAnno.getOriginal(); assertThat(anno.considerBlank()).isEqualTo(true); assertThat(anno.considerEmpty()).isEqualTo(true); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.min()).isEqualTo("2"); assertThat(anno.max()).isEqualTo("2"); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("5"); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(7); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 属性のオーバーライドあり * <p>共通の属性の上書き</p> */ @Test public void testExpand_composeOverrideDefault1() { Field field = getSampleField("composeOverrideDefault1"); Annotation targetAnno = field.getAnnotation(ComposeOverrideDefault1.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeOverrideDefault1.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(8); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvRequire.class); CsvRequire anno = (CsvRequire) childAnno.getOriginal(); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Read, BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("30"); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Read, BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("20"); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Read, BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(7); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 属性のオーバーライドあり * <p>共通の属性の上書き</p> * <p>1部の属性を上書き</p> */ @Test public void testExpand_composeOverrideDefault2() { Field field = getSampleField("composeOverrideDefault2"); Annotation targetAnno = field.getAnnotation(ComposeOverrideDefault2.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeOverrideDefault2.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(8); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvRequire.class); CsvRequire anno = (CsvRequire) childAnno.getOriginal(); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("30"); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Read, BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("20"); assertThat(anno.message()).isEqualTo("範囲内に設定してください"); assertThat(anno.groups()).containsExactly(Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(7); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 属性のオーバーライドあり * <p>共通の属性の上書き</p> * <p>1部の属性を上書き</p> */ @Test public void testExpand_composeOverrideDefault3() { Field field = getSampleField("composeOverrideDefault3"); Annotation targetAnno = field.getAnnotation(ComposeOverrideDefault3.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeOverrideDefault3.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(8); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvRequire.class); CsvRequire anno = (CsvRequire) childAnno.getOriginal(); assertThat(anno.message()).isEqualTo("必須です"); assertThat(anno.groups()).containsExactly(Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("30"); assertThat(anno.message()).isEqualTo("{com.github.mygreen.supercsv.annotation.constraint.CsvNumberRange.message}"); assertThat(anno.groups()).hasSize(0); assertThat(anno.cases()).hasSize(0); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("20"); assertThat(anno.message()).isEqualTo("値は不正です"); assertThat(anno.groups()).containsExactly(DefaultGroup.class, Group2.class); assertThat(anno.cases()).containsExactly(BuildCase.Read, BuildCase.Write); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(7); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 属性のオーバーライドあり * <p>属性名の省略</p> * <p>1部の属性を上書き</p> */ @Test public void testExpand_composeOverrideDefault4() { Field field = getSampleField("composeOverrideDefault4"); Annotation targetAnno = field.getAnnotation(ComposeOverrideDefault4.class); List<ExpandedAnnotation> actual = expander.expand(targetAnno); assertThat(actual).hasSize(1); { ExpandedAnnotation expandedAnno = actual.get(0); assertThat(expandedAnno.getOriginal()).isInstanceOf(ComposeOverrideDefault4.class); assertThat(expandedAnno.getIndex()).isEqualTo(0); assertThat(expandedAnno.getChilds()).hasSize(7); { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(0); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(1); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(1); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("30"); assertThat(anno.message()).isEqualTo("{com.github.mygreen.supercsv.annotation.constraint.CsvNumberRange.message}"); assertThat(anno.groups()).hasSize(0); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(1); assertThat(childAnno.getOriginal()).isInstanceOf(CsvNumberRange.class); assertThat(childAnno.getIndex()).isEqualTo(0); CsvNumberRange anno = (CsvNumberRange) childAnno.getOriginal(); assertThat(anno.order()).isEqualTo(2); assertThat(anno.min()).isEqualTo("0"); assertThat(anno.max()).isEqualTo("5"); assertThat(anno.groups()).containsExactly(Group1.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(2); assertThat(childAnno.getOriginal()).isInstanceOf(CsvComposition.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(3); assertThat(childAnno.getOriginal()).isInstanceOf(Documented.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(4); assertThat(childAnno.getOriginal()).isInstanceOf(Repeatable.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(5); assertThat(childAnno.getOriginal()).isInstanceOf(Retention.class); } { ExpandedAnnotation childAnno = expandedAnno.getChilds().get(6); assertThat(childAnno.getOriginal()).isInstanceOf(Target.class); } } } /** * 合成のアノテーション - 上書き対象の属性が見つからない場合 */ @Test public void testExpand_composeOverrideNotFoundAttr1() { Field field = getSampleField("composeOverrideAttrNotFound1"); Annotation targetAnno = field.getAnnotation(ComposeOverrideAttrNotFound1.class); assertThatThrownBy(() -> expander.expand(targetAnno)) .isInstanceOf(SuperCsvInvalidAnnotationException.class) .hasMessage("アノテーション @ComposeOverrideAttrNotFound1 において、アノテーション @CsvOverridesAnnotation で上書きするアノテーション @CsvNumberRange の属性(java.lang.String test) が見つかりません。"); } /** * 合成のアノテーション - 上書き対象の属性が見つからない場合 * - インデックス指定 */ @Test public void testExpand_composeOverrideNotFoundAttr2() { Field field = getSampleField("composeOverrideAttrNotFound2"); Annotation targetAnno = field.getAnnotation(ComposeOverrideAttrNotFound2.class); //TODO: 現状は正常終了してしまう。 // assertThatThrownBy(() -> expander.expand(targetAnno)) // .isInstanceOf(SuperCsvInvalidAnnotationException.class) // .hasMessage("アノテーション @ComposeOverrideAttrNotFound2 において、アノテーション @CsvOverridesAnnotation で上書きするアノテーション 1番目の @CsvNumberRange の属性(java.lang.String test) が見つかりません。"); // } /** * テスト用のクラスのフィールドを取得する * @param fieldName 取得し対象のフィールドの名称 * @return */ private static Field getSampleField(final String fieldName) { try { final Field field = SampleCsv.class.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch(Exception e) { throw new RuntimeException(String.format("fail get field : '%s'.", fieldName), e); } } private static class SampleCsv { @CsvColumn(number=1, label="test") private int normal; @CsvDateTimeFormat(pattern="yyyy/MM/dd") @CsvColumn(number=2, label="test") @CsvDateTimeMax(value="2050/10/21", order=5) @CsvUnique(order=3) @CsvLower(order=1) @CsvTrim(order=10) private Date multi; @CsvLengthMax(value=10) private String repeatSingle; @CsvLengthMax(value=10) @CsvLengthMax(value=20) @CsvLengthMax(value=30) private String repeatMulti; @ComposeSimple(value="simple") private Integer composeSimple; @ComposeSimple(value="repeat-1") @ComposeSimple(value="repeat-2") private Integer composeSimpleRepeat; @ComposeOverrideCustom(value="override-custom", max1="5") private Integer composeOverrideCustom; @ComposeOverrideDefault1(value="override-default-1", message="値は不正です", groups={DefaultGroup.class, Group2.class}, cases={BuildCase.Read, BuildCase.Write}) private Integer composeOverrideDefault1; @ComposeOverrideDefault2(value="override-default-2", message="値は不正です", groups={DefaultGroup.class, Group2.class}, rangeMessage="範囲内に設定してください", rangeGroups={Group2.class}, rangeCases={BuildCase.Read, BuildCase.Write}) private Integer composeOverrideDefault2; @ComposeOverrideDefault3(value="override-default-3", message="値は不正です", groups={DefaultGroup.class, Group2.class}, cases={BuildCase.Read, BuildCase.Write}) private Integer composeOverrideDefault3; @ComposeOverrideDefault4(value="override-default-4", max="5") private Integer composeOverrideDefault4; // エラー確認用 @ComposeOverrideAttrNotFound1(value="v", test="t") private Integer composeOverrideAttrNotFound1; @ComposeOverrideAttrNotFound2(value="v", test="t") private Integer composeOverrideAttrNotFound2; } // テスト用のグループ1 private interface Group1 { } // テスト用のグループ2 private interface Group2 { } /** * 合成のアノテーション * <p>属性の上書きはなし</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeSimple.List.class) @CsvComposition @CsvRequire @CsvNumberMax(value="20", order=2) @CsvNumberMax(value="30", order=1) public static @interface ComposeSimple { String value(); // 繰り返しのアノテーションの格納用アノテーションの定義 @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeSimple[] value(); } } /** * 合成のアノテーション * <p>属性の上書きあり</p> * <p>固有の属性をオーバーライドする</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideCustom.List.class) @CsvComposition @CsvRequire(considerBlank=false, considerEmpty=false, message="必須です") @CsvNumberRange(min="0", max="20", order=2) @CsvNumberRange(min="0", max="30", order=1) public static @interface ComposeOverrideCustom { String value(); @CsvOverridesAttribute(annotation=CsvRequire.class, name="considerBlank") @CsvOverridesAttribute(annotation=CsvRequire.class, name="considerEmpty") boolean considerSpace() default true; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="max", index=0) String max1(); @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="max", index=1) @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="min", index=1) String max2() default "2"; @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideCustom[] value(); } } /** * 合成のアノテーション * <p>属性の上書きあり</p> * <p>共通の属性 message groups casesのをオーバーライドする</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideDefault1.List.class) @CsvComposition @CsvRequire(message="必須です", groups={Group2.class}) @CsvNumberRange(min="0", max="20", order=2, groups={Group1.class}, cases=BuildCase.Read) @CsvNumberRange(min="0", max="30", order=1, cases=BuildCase.Write) public static @interface ComposeOverrideDefault1 { String value(); String message() default ""; Class<?>[] groups() default {}; BuildCase[] cases() default {}; @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideDefault1[] value(); } } /** * 合成のアノテーション * <p>属性の上書きあり</p> * <p>共通の属性のmessage, groups, casesをオーバーライドする</p> * <p>1部のみを書き換える。</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideDefault2.List.class) @CsvComposition @CsvRequire(message="必須です", groups={Group2.class}) @CsvNumberRange(min="0", max="20", order=2, groups={Group1.class}, cases=BuildCase.Write) @CsvNumberRange(min="0", max="30", order=1, cases=BuildCase.Read) public static @interface ComposeOverrideDefault2 { String value(); String message() default ""; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="message", index=0) String rangeMessage() default ""; Class<?>[] groups() default {}; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="groups", index=0) Class<?>[] rangeGroups() default {}; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="cases", index=1) BuildCase[] rangeCases() default {}; @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideDefault2[] value(); } } /** * 合成のアノテーション * <p>属性の上書きあり</p> * <p>cases、messageやgroupsの共通の属性をオーバーライドする</p> * <p>1部のみを書き換える。</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideDefault3.List.class) @CsvComposition @CsvRequire(message="必須です", groups={Group2.class}, cases={BuildCase.Write}) @CsvNumberRange(min="0", max="20", order=2, groups={Group1.class}, cases={BuildCase.Read}) @CsvNumberRange(min="0", max="30", order=1) public static @interface ComposeOverrideDefault3 { String value(); @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="message", index=0) String message() default ""; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="cases", index=0) BuildCase[] cases() default {}; @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="groups", index=0) Class<?>[] groups() default {}; @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideDefault3[] value(); } } /** * 合成のアノテーション * <p>属性の上書きあり</p> * <p>属性名の省略</p> * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @CsvComposition @Repeatable(ComposeOverrideDefault4.List.class) @CsvNumberRange(min="0", max="20", order=2, groups={Group1.class}) @CsvNumberRange(min="0", max="30", order=1) public static @interface ComposeOverrideDefault4 { String value(); @CsvOverridesAttribute(annotation=CsvNumberRange.class, index=0) String max(); @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideDefault4[] value(); } } /** * 合成のアノテーション * 一致する上書き対象の属性が見つからない場合 * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideAttrNotFound1.List.class) @CsvComposition @CsvRequire(message="必須です") @CsvNumberRange(min="0", max="30", order=1) public static @interface ComposeOverrideAttrNotFound1 { String value(); // 存在しない属性 @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="test") String test(); @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideAttrNotFound1[] value(); } } /** * 合成のアノテーション * 一致する上書き対象の属性が見つからない場合 * - インデックスが一致しない * */ @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(ComposeOverrideAttrNotFound2.List.class) @CsvComposition @CsvRequire(message="必須です") @CsvNumberRange(min="0", max="30", order=1) public static @interface ComposeOverrideAttrNotFound2 { String value(); // 存在しない属性 - インデックスが不正 @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="test", index=1) String test(); @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { ComposeOverrideAttrNotFound2[] value(); } } }